package nancal.mp.util

import nancal.mp.db.mongo.entity.dev.JenkinsLogItemData
import nbcp.base.comm.ListResult
import nbcp.base.comm.const
import nbcp.base.extend.HasValue
import nbcp.base.extend.Slice

object JenkinsUtil {

    /**
     * 分析Jenkins日志
     */
    fun analyse(content: String): ListResult<JenkinsLogItemData> {
        var lines = content.replace("\r\n", "\n").split("\n");

        if (lines.any { it == "[Pipeline] stage" }) {
            /*
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (检查启动)
             */
            return pipelineStyle(lines)
        }

        return freeStyle(lines);
    }

    /**
     * 自定义格式！
     */
    private fun freeStyle(lines: List<String>): ListResult<JenkinsLogItemData> {
        var list = mutableListOf<JenkinsLogItemData>()


        var i = -1;
        while (true) {
            i++;
            if ((i + 1) >= lines.size - 1) {
                break;
            }

            var line = lines[i]
            if (line.startsWith("[[") && line.endsWith("]]")) {
                //[标题]
                var title = line.Slice(2, -2);

                var contents = get_free_contents(i, lines);
                i = i + contents.size;

                //设置上一个阶段的结果
                if (list.any()) {
                    list.last().successful = true;
                }

                list.add(JenkinsLogItemData(title, null, contents.joinToString("\n")));
            }
        }

        var result: Boolean? = null
        if (list.any()) {
            var lastStep = list.last();
            var lastLine = lines.last { it.HasValue }.trim()
            if (lastLine.startsWith("Finished:")) {
                if (lastLine == "Finished: SUCCESS") {
                    lastStep.successful = true;
                    result = true
                } else {
                    lastStep.successful = false;
                    result = false
                }
            }
        }

        var maxLength = 40960
        list.forEach {
            if (it.content.length > maxLength) {
                it.content = it.content.substring(0, maxLength / 2) + "\n...\n" + it.content.Slice(-maxLength / 2);
            }
        }

        return ListResult.of(list).withValue(result);
    }


    private fun get_free_contents(startIndex: Int, lines: List<String>): List<String> {
        var contents = mutableListOf<String>()
        var j = startIndex;
        while (true) {
            j++;
            if (j >= lines.size - 1) {
                break;
            }

            var line = lines[j];

            if (line.startsWith("[[") && line.endsWith("]]")) {
                break;
            }
            contents.add(line)
        }

        return contents;
    }

    /**
     * 标准流水线格式
     */
    private fun pipelineStyle(lines: List<String>): ListResult<JenkinsLogItemData> {
        var list = mutableListOf<JenkinsLogItemData>()

        var lastDetails = mutableListOf<String>()
        var i = -1;
        while (true) {
            i++;
            if ((i + 1) >= lines.size - 1) {
                break;
            }
            var line = lines[i]
            if (line == "[Pipeline] stage") {
                i++;
                line = lines[i];


                //[Pipeline] { (K8s部署)
                var title = line.substring("[Pipeline] { (".length, line.length - 1)

                var contents = get_pipeline_contents(i, lines);

                /*
Stage "推送镜像" skipped due to earlier failure(s)
getContext
                 */
                if (contents.size > 0 && contents.first().startsWith("Stage ") &&
                    contents.first().endsWith(" skipped due to earlier failure(s)")
                ) {
                    list.last().successful = false;
                    break;
                } else if (list.any()) {
                    list.last().successful = true;
                }

                i = i + contents.size;

                list.add(JenkinsLogItemData(title, null, contents.joinToString("\n")));
            }
            //获取异常
            else if (line == "[Pipeline] End of Pipeline") {
                lastDetails = get_exception(i, lines);
            }
        }

        var result: Boolean? = null
        if (list.any()) {
            var lastStep = list.last();
            var lastLine = lines.last { it.HasValue }.trim()
            if (lastLine.startsWith("Finished:")) {
                if (lastLine == "Finished: SUCCESS") {
                    if (lastStep.successful == null) {
                        lastStep.successful = true;
                    }
                    result = true
                } else {
                    lastStep.successful = false;
                    result = false
                }


                if (lastDetails.any()) {
                    lastStep.content = lastStep.content + const.line_break + lastDetails.joinToString("\n")
                }
            }
        }

        var maxLength = 40960
        list.forEach {
            if (it.content.length > maxLength) {
                it.content = it.content.substring(0, maxLength / 2) + "\n...\n" + it.content.Slice(-maxLength / 2);
            }
        }

        return ListResult.of(list).withValue(result);
    }

    private fun get_exception(startIndex: Int, lines: List<String>): MutableList<String> {
        var contents = mutableListOf<String>()
        var j = startIndex;
        while (true) {
            j++;
            if (j >= lines.size - 1) {
                break;
            }

            var line = lines[j];



            if (line.startsWith("Finished: ")) {
                break;
            }

            //ERROR: script returned exit code 1
            contents.add(line)
        }

        return contents;
    }

    private fun get_pipeline_contents(startIndex: Int, lines: List<String>): List<String> {
        var contents = mutableListOf<String>()
        var j = startIndex;
        while (true) {
            j++;
            if (j >= lines.size - 1) {
                break;
            }

            var line = lines[j];

            if (line.startsWith("[Pipeline] ")) {
                if (line.startsWith("[Pipeline] }") && lines[j + 1] == "[Pipeline] // stage") {
                    break;
                }
                line = line.Slice("[Pipeline] ".length)
            }
            contents.add(line)
        }

        return contents;
    }
}